package com.och.mrcp.util;

import lombok.extern.slf4j.Slf4j;

import javax.sound.sampled.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * 音频格式转换工具
 * 支持不同采样率、位深度和声道数之间的转换
 */
@Slf4j
public class AudioConverter {
    
    /**
     * 转换音频格式
     */
    public static byte[] convertAudio(byte[] audioData, 
                                    AudioFormat sourceFormat, 
                                    AudioFormat targetFormat) throws IOException {
        
        if (audioData == null || audioData.length == 0) {
            return new byte[0];
        }
        
        // 如果格式相同，直接返回
        if (isFormatEqual(sourceFormat, targetFormat)) {
            return audioData;
        }
        
        try {
            log.debug("Converting audio: {} -> {}", formatToString(sourceFormat), formatToString(targetFormat));
            
            // 创建音频输入流
            ByteArrayInputStream bais = new ByteArrayInputStream(audioData);
            AudioInputStream sourceStream = new AudioInputStream(bais, sourceFormat, audioData.length / sourceFormat.getFrameSize());
            
            // 检查是否支持直接转换
            if (AudioSystem.isConversionSupported(targetFormat, sourceFormat)) {
                // 直接转换
                AudioInputStream targetStream = AudioSystem.getAudioInputStream(targetFormat, sourceStream);
                return readAudioStream(targetStream);
            } else {
                // 分步转换：先转换为PCM，再转换为目标格式
                return convertViaPCM(audioData, sourceFormat, targetFormat);
            }
            
        } catch (IOException e) {
            log.error("Audio conversion failed: {} -> {}", formatToString(sourceFormat), formatToString(targetFormat), e);
            throw new IOException("Audio conversion failed", e);
        } catch (Exception e) {
            log.error("Unexpected error during audio conversion: {} -> {}", formatToString(sourceFormat), formatToString(targetFormat), e);
            throw new IOException("Audio conversion failed", e);
        }
    }
    
    /**
     * 通过PCM中间格式进行转换
     */
    private static byte[] convertViaPCM(byte[] audioData, AudioFormat sourceFormat, AudioFormat targetFormat) throws IOException {
        try {
            // 创建中间PCM格式
            AudioFormat pcmFormat = new AudioFormat(
                AudioFormat.Encoding.PCM_SIGNED,
                sourceFormat.getSampleRate(),
                16, // 16位
                sourceFormat.getChannels(),
                sourceFormat.getChannels() * 2, // 16位 = 2字节
                sourceFormat.getSampleRate(),
                false // little-endian
            );
            
            // 第一步：转换为PCM
            byte[] pcmData = audioData;
            if (!isFormatEqual(sourceFormat, pcmFormat)) {
                ByteArrayInputStream bais = new ByteArrayInputStream(audioData);
                AudioInputStream sourceStream = new AudioInputStream(bais, sourceFormat, audioData.length / sourceFormat.getFrameSize());
                AudioInputStream pcmStream = AudioSystem.getAudioInputStream(pcmFormat, sourceStream);
                pcmData = readAudioStream(pcmStream);
            }
            
            // 第二步：从PCM转换为目标格式
            if (!isFormatEqual(pcmFormat, targetFormat)) {
                ByteArrayInputStream bais = new ByteArrayInputStream(pcmData);
                AudioInputStream pcmStream = new AudioInputStream(bais, pcmFormat, pcmData.length / pcmFormat.getFrameSize());
                AudioInputStream targetStream = AudioSystem.getAudioInputStream(targetFormat, pcmStream);
                return readAudioStream(targetStream);
            }
            
            return pcmData;
            
        } catch (Exception e) {
            log.error("PCM conversion failed", e);
            throw new IOException("PCM conversion failed", e);
        }
    }
    
    /**
     * 采样率转换
     */
    public static byte[] resample(byte[] audioData, int sourceSampleRate, int targetSampleRate, int channels) {
        if (sourceSampleRate == targetSampleRate) {
            return audioData;
        }
        
        log.debug("Resampling audio: {}Hz -> {}Hz, channels: {}", sourceSampleRate, targetSampleRate, channels);
        
        // 简单的线性插值重采样
        double ratio = (double) targetSampleRate / sourceSampleRate;
        int bytesPerSample = 2; // 假设16位PCM
        int frameSize = channels * bytesPerSample;
        
        int sourceFrames = audioData.length / frameSize;
        int targetFrames = (int) (sourceFrames * ratio);
        
        byte[] result = new byte[targetFrames * frameSize];
        ByteBuffer sourceBuffer = ByteBuffer.wrap(audioData).order(ByteOrder.LITTLE_ENDIAN);
        ByteBuffer targetBuffer = ByteBuffer.wrap(result).order(ByteOrder.LITTLE_ENDIAN);
        
        for (int i = 0; i < targetFrames; i++) {
            double sourceIndex = i / ratio;
            int index1 = (int) sourceIndex;
            int index2 = Math.min(index1 + 1, sourceFrames - 1);
            double fraction = sourceIndex - index1;
            
            for (int ch = 0; ch < channels; ch++) {
                short sample1 = sourceBuffer.getShort((index1 * frameSize) + (ch * bytesPerSample));
                short sample2 = sourceBuffer.getShort((index2 * frameSize) + (ch * bytesPerSample));
                
                // 线性插值
                short interpolated = (short) (sample1 + fraction * (sample2 - sample1));
                targetBuffer.putShort(interpolated);
            }
        }
        
        return result;
    }
    
    /**
     * 音量调节
     */
    public static byte[] adjustVolume(byte[] audioData, double volumeScale) {
        if (volumeScale == 1.0) {
            return audioData;
        }
        
        byte[] result = new byte[audioData.length];
        ByteBuffer buffer = ByteBuffer.wrap(audioData).order(ByteOrder.LITTLE_ENDIAN);
        ByteBuffer resultBuffer = ByteBuffer.wrap(result).order(ByteOrder.LITTLE_ENDIAN);
        
        for (int i = 0; i < audioData.length; i += 2) {
            short sample = buffer.getShort(i);
            int adjusted = (int) (sample * volumeScale);
            
            // 防止溢出
            adjusted = Math.max(Short.MIN_VALUE, Math.min(Short.MAX_VALUE, adjusted));
            
            resultBuffer.putShort(i, (short) adjusted);
        }
        
        return result;
    }
    
    /**
     * 创建标准RTP音频格式
     */
    public static AudioFormat createRtpAudioFormat(int sampleRate, int channels) {
        return new AudioFormat(
            AudioFormat.Encoding.PCM_SIGNED,
            sampleRate,
            16, // 16位
            channels,
            channels * 2, // 帧大小
            sampleRate,
            false // little-endian
        );
    }
    
    /**
     * 从音频流读取所有数据
     */
    private static byte[] readAudioStream(AudioInputStream stream) throws IOException {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            
            while ((bytesRead = stream.read(buffer)) != -1) {
                baos.write(buffer, 0, bytesRead);
            }
            
            return baos.toByteArray();
        } finally {
            stream.close();
        }
    }
    
    /**
     * 比较两个音频格式是否相等
     */
    private static boolean isFormatEqual(AudioFormat format1, AudioFormat format2) {
        return format1.getEncoding().equals(format2.getEncoding()) &&
               Math.abs(format1.getSampleRate() - format2.getSampleRate()) < 0.1 &&
               format1.getSampleSizeInBits() == format2.getSampleSizeInBits() &&
               format1.getChannels() == format2.getChannels() &&
               format1.isBigEndian() == format2.isBigEndian();
    }
    
    /**
     * 格式转换为字符串
     */
    private static String formatToString(AudioFormat format) {
        return String.format("%s, %.1fHz, %d-bit, %d channels, %s",
                format.getEncoding(),
                format.getSampleRate(),
                format.getSampleSizeInBits(),
                format.getChannels(),
                format.isBigEndian() ? "big-endian" : "little-endian");
    }
    
    /**
     * 检测音频数据的格式
     */
    public static AudioFormat detectAudioFormat(byte[] audioData) {
        // 简单的格式检测，实际应该更复杂
        // 这里假设是16位PCM，立体声，44.1kHz
        return new AudioFormat(
            AudioFormat.Encoding.PCM_SIGNED,
            44100.0f,
            16,
            2,
            4,
            44100.0f,
            false
        );
    }
}
